package com.feng.freader.view.sudo.bus;

//import static secondriver.sudo.view.NineGridView.NUM;
//import static secondriver.sudo.view.NineGridView.SIZE;
//import static secondriver.sudo.view.NineGridView.ZERO;

import static com.feng.freader.view.sudo.view.NineGridView.NUM;
import static com.feng.freader.view.sudo.view.NineGridView.SIZE;
import static com.feng.freader.view.sudo.view.NineGridView.ZERO;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class Game {

	private final int[] originalStatus;
	private final int[] initialStatus;
	private int[] currentStatus;

	private Integer[] unUsedNumber = new Integer[] { ZERO };

	private boolean gameHint = true;

	private Game(int[] originalStatus, int[] initialStatus, int[] currentStatus) {
		this.originalStatus = originalStatus;
		this.initialStatus = initialStatus;
		this.currentStatus = currentStatus;
	}

	public static Game obtainGameFromGameLevel(GameLevel level) {
		int[] os = GameData.getGameOriginalStatus();
		int[] is = GameData.getGameInitialStatus(level, os);
		int[] cs = Arrays.copyOf(is, is.length);
		Game game = new Game(os, is, cs);
		if (level.getV() > GameLevel.INTERMEDIATE.getV()) {
			game.gameHint = false;
		}
		return game;
	}

	public static Game obtainGameFromString(String value) {
		int length = SIZE * SIZE;
		int size = length * 3;
		if (null == value || value.length() != size) {
			throw new IllegalArgumentException(
					"Preference value not valid, it should length equals "
							+ size);
		}
		int[] v = new int[size];
		for (int i = 0, l = size; i < l; i++) {
			v[i] = value.charAt(i) - '0';
		}

		return new Game(Arrays.copyOfRange(v, 0, length), Arrays.copyOfRange(v,
				length, length * 2), Arrays.copyOfRange(v, length * 2,
				length * 3));
	}

	public static String obtainGameToString(Game game) {
		return (Arrays.toString(game.originalStatus)
				+ Arrays.toString(game.initialStatus) + Arrays
					.toString(game.currentStatus)).replaceAll("[\\[\\], ]", "");
	}

	public boolean isInalidate(int x, int y, Integer number) {
		if (getCurrentStatusValue(x, y).equals(number)) {
			return false;
		} else {
			setCurrentStatusValue(x, y, number);
			return true;
		}
	}

	public String getCurrentStatusText(int x, int y) {
		Integer v = getCurrentStatusValue(x, y);
		if (v.intValue() == ZERO) {
			return "";
		} else {
			return "" + v;
		}
	}

	public Integer getCurrentStatusValue(int x, int y) {
		int index = x + SIZE * y;
		return currentStatus[index];
	}

	private void setCurrentStatusValue(int x, int y, Integer number) {
		int index = x + SIZE * y;
		currentStatus[index] = number;
	}

	public Integer[] reCalculateUnUsedNumber(int x, int y) {
		Set<Integer> set = new HashSet<Integer>();
		for (int i = 1; i <= SIZE; i++) {
			set.add(i);
		}
		for (int i = 0; i < SIZE; i++) {
			Integer vY = getCurrentStatusValue(x, i);
			if (vY != ZERO) {
				set.remove(vY);
			}
			Integer vX = getCurrentStatusValue(i, y);
			if (vX != ZERO) {
				set.remove(vX);
			}
		}
		int sX = x / NUM * NUM;
		int sY = y / NUM * NUM;
		for (int i = sX, si = sX + NUM; i < si; i++) {
			for (int j = sY, sj = sY + NUM; j < sj; j++) {
				Integer v = getCurrentStatusValue(i, j);
				if (v != ZERO) {
					set.remove(v);
				}
			}
		}
		set.add(ZERO);
		unUsedNumber = new Integer[set.size()];
		Iterator<Integer> iter = set.iterator();
		int index = 0;
		while (iter.hasNext()) {
			unUsedNumber[index] = iter.next();
			index++;
		}
		Arrays.sort(unUsedNumber);
		return unUsedNumber;
	}

	public Integer[] getUnUsedNumber() {
		return this.unUsedNumber;
	}

	public void setCurrentStatusFromOriginalStatus() {
		currentStatus = Arrays.copyOf(originalStatus, originalStatus.length);
	}

	public void recoverCurrentStatusFromInitialStatus() {
		currentStatus = Arrays.copyOf(initialStatus, initialStatus.length);
	}

	public boolean isInitialStatusValue(int x, int y) {
		int index = x + SIZE * y;
		int v = initialStatus[index];
		return v != ZERO;
	}

	public boolean isWon() {
		for (int i = 0; i < originalStatus.length; i++) {
			if (currentStatus[i] != originalStatus[i]) {
				return false;
			}
		}
		return true;
	}

	public boolean isHint() {
		return gameHint;
	}
}
